package com.github.fancyideas.jwt;

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    private final AuthenticationManager authenticationManager;
    private final JwtConfigurationProperties jwtConfigurationProperties;

    public JwtAuthenticationFilter(AuthenticationManager authenticationManager,
                                   JwtConfigurationProperties jwtConfigurationProperties) {
        this.authenticationManager = authenticationManager;
        setFilterProcessesUrl(jwtConfigurationProperties.getAuthLoginUrl());
        this.jwtConfigurationProperties = jwtConfigurationProperties;
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request,
                                                HttpServletResponse response) {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(username, password);
        return authenticationManager.authenticate(authenticationToken);
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request,
                                            HttpServletResponse response,
                                            FilterChain filterChain,
                                            Authentication authentication) {
        User user = ((User) authentication.getPrincipal());
        List roles = user.getAuthorities()
                .stream()
                .map(GrantedAuthority::getAuthority)
                .collect(Collectors.toList());
        byte[] signingKey = jwtConfigurationProperties.getJwtSecret().getBytes();
        String token = Jwts.builder()
                .signWith(Keys.hmacShaKeyFor(signingKey), SignatureAlgorithm.HS512)
                .setHeaderParam("typ", jwtConfigurationProperties.getTokenType())
                .setIssuer(jwtConfigurationProperties.getTokenIssuer())
                .setAudience(jwtConfigurationProperties.getTokenAudience())
                .setSubject(user.getUsername())
                .setExpiration(new Date(System.currentTimeMillis() + jwtConfigurationProperties.getExpiration()))
                .claim("rol", roles)
                .compact();
        response.addHeader(
                jwtConfigurationProperties.getTokenHeader(),
                jwtConfigurationProperties.getTokenPrefix() + token);
    }

}
